home *** CD-ROM | disk | FTP | other *** search
- //-----------------------------------------------------------------------------
- // File: flexcombobox.cpp
- //
- // Desc: Implements a combo box control similar to Windows combo box.
- // CFlexComboBox is derived from CFlexWnd. It is used by the page
- // for player list and genre list. When the combo box is open,
- // CFlexComboBox uses a CFlexListBox for the list window.
- //
- // Copyright (C) Microsoft Corporation. All Rights Reserved.
- //-----------------------------------------------------------------------------
-
- #include "common.hpp"
-
-
- CFlexComboBox::CFlexComboBox() :
- m_nTextHeight(-1),
- m_hWndNotify(NULL),
- m_rgbText(RGB(255,255,255)),
- m_rgbBk(RGB(0,0,0)),
- m_rgbSelText(RGB(0,0,255)),
- m_rgbSelBk(RGB(0,0,0)),
- m_rgbFill(RGB(0,0,255)),
- m_rgbLine(RGB(0,255,255)),
- m_dwFlags(0),
- m_dwListBoxFlags(0),
- m_bInSelMode(FALSE),
- m_nSBWidth(11),
- m_hFont(NULL),
- m_eCurState(FCBS_CLOSED),
- m_OldSel(-1)
- {
- }
-
- CFlexComboBox::~CFlexComboBox()
- {
- }
-
- CFlexComboBox *CreateFlexComboBox(FLEXCOMBOBOXCREATESTRUCT *pcs)
- {
- CFlexComboBox *psb = new CFlexComboBox;
-
- if (psb && psb->Create(pcs))
- return psb;
-
- delete psb;
- return NULL;
- }
-
- BOOL CFlexComboBox::Create(FLEXCOMBOBOXCREATESTRUCT *pcs)
- {
- if (this == NULL)
- return FALSE;
-
- if (pcs == NULL)
- return FALSE;
-
- if (pcs->dwSize != sizeof(FLEXCOMBOBOXCREATESTRUCT))
- return FALSE;
-
- m_hWndNotify = pcs->hWndNotify ? pcs->hWndNotify : pcs->hWndParent;
-
- m_dwFlags = pcs->dwFlags;
- m_dwListBoxFlags = pcs->dwListBoxFlags;
-
- SetFont(pcs->hFont);
- SetColors(pcs->rgbText, pcs->rgbBk, pcs->rgbSelText, pcs->rgbSelBk, pcs->rgbFill, pcs->rgbLine);
- m_nSBWidth = pcs->nSBWidth;
- m_rect = pcs->rect;
-
- if (!CFlexWnd::Create(pcs->hWndParent, GetRect(pcs->rect), pcs->bVisible))
- return FALSE;
-
-
- return TRUE;
- }
-
- void CFlexComboBox::OnPaint(HDC hDC)
- {
- HDC hBDC = NULL, hODC = NULL;
- CBitmap *pbm = NULL;
-
- if (!InRenderMode())
- {
- hODC = hDC;
- pbm = CBitmap::Create(GetClientSize(), RGB(0,0,0), hDC);
- if (pbm != NULL)
- {
- hBDC = pbm->BeginPaintInto();
- if (hBDC != NULL)
- {
- hDC = hBDC;
- }
- }
- }
-
- InternalPaint(hDC);
-
- if (!InRenderMode())
- {
- if (pbm != NULL)
- {
- if (hBDC != NULL)
- {
- pbm->EndPaintInto(hBDC);
- pbm->Draw(hODC);
- }
- delete pbm;
- }
- }
- }
-
- void CFlexComboBox::SetSel(int i)
- {
- m_ListBox.SelectAndShowSingleItem(i, TRUE);
- }
-
- int CFlexComboBox::GetSel()
- {
- return m_ListBox.GetSel();
- }
-
- LPCTSTR CFlexComboBox::GetText()
- {
- return m_ListBox.GetSelText();
- }
-
- void CFlexComboBox::InternalPaint(HDC hDC)
- {
- HGDIOBJ hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbLine);
- if (hPen != NULL)
- {
- HGDIOBJ hOldPen = SelectObject(hDC, hPen);
-
- HGDIOBJ hBrush = (HGDIOBJ)CreateSolidBrush(m_rgbBk);
- if (hBrush != NULL)
- {
- HGDIOBJ hOldBrush = SelectObject(hDC, hBrush);
-
- RECT rect = {0,0,0,0};
- GetClientRect(&rect);
- Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
-
- RECT arect = rect;
-
- arect.left = arect.right - (arect.bottom - arect.top);
-
- // If we are read-only, only draw the text in gray. No border, no arrow.
- if (!GetReadOnly())
- {
- MoveToEx(hDC, arect.left, arect.top, NULL);
- LineTo(hDC, arect.left, arect.bottom);
- }
-
- rect.left++;
- rect.top++;
- rect.right = arect.left;
- rect.bottom--;
-
- SetTextColor(hDC, m_rgbText);
- SetBkMode(hDC, TRANSPARENT);
-
- LPTSTR lpText = (LPTSTR)GetText();
- if (lpText)
- {
- DrawText(hDC, lpText, -1, &rect, DT_NOPREFIX);
- }
-
- SelectObject(hDC, hOldBrush);
- DeleteObject(hBrush);
-
- if (!GetReadOnly())
- {
- hBrush = (HGDIOBJ)CreateSolidBrush(m_rgbFill);
- if (hBrush != NULL)
- {
- SelectObject(hDC, hBrush);
-
- InflateRect(&arect, -3, -3);
- DrawArrow(hDC, arect, TRUE, FALSE);
-
- SelectObject(hDC, hOldBrush);
- DeleteObject(hBrush);
- }
- }
- }
-
- SelectObject(hDC, hOldPen);
- DeleteObject(hPen);
- }
- }
-
- int CFlexComboBox::AddString(LPCTSTR str)
- {
- return m_ListBox.AddString(str);
- }
-
- LRESULT CFlexComboBox::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- RECT wrect = {-1, -1, -1, -1};
- POINT point = {-1, -1};
- BOOL bWithin = FALSE;
-
- switch (msg)
- {
- case WM_SIZE:
- Invalidate();
- SetRect();
- return 0;
-
- case WM_FLEXLISTBOX:
- assert(lParam == (LPARAM)(LPVOID)&m_ListBox);
- switch (wParam)
- {
- case FLBN_FINALSEL:
- StateEvent(FCBSE_UPLIST);
- break;
- case FLBN_CANCEL:
- StateEvent(FCBSE_DOWNOFF);
- break;
- }
- return 0;
-
- // make sure flexwnd doesn't do ANYTHING with our mouse messages
- case WM_MOUSEMOVE:
- // We initialize the tooltip to current selection text if the selected text is too long to fit.
- RECT rect;
- GetClientRect(&rect);
- rect.right = rect.right - (rect.bottom - rect.top);
- rect.left++;
- rect.top++;
- rect.bottom--;
- RECT ResultRect;
- ResultRect = rect;
- HDC hDC;
- hDC = CreateCompatibleDC(NULL);
- if (hDC)
- {
- LPTSTR lpText = (LPTSTR)GetText();
- if (lpText)
- {
- DrawText(hDC, lpText, -1, &ResultRect, DT_NOPREFIX|DT_CALCRECT);
- }
- DeleteDC(hDC);
- }
- if (rect.right < ResultRect.right || rect.bottom < ResultRect.bottom)
- {
- CFlexWnd::s_ToolTip.SetToolTipParent(GetParent(m_hWnd));
- TOOLTIPINITPARAM ttip;
- ttip.hWndParent = GetParent(m_hWnd);
- ttip.iSBWidth = 0;
- ttip.dwID = 0;
- ttip.hWndNotify = m_hWnd;
- ttip.tszCaption = m_ListBox.GetSelText();
- CFlexToolTip::UpdateToolTipParam(ttip);
- }
- Notify(FCBN_MOUSEOVER);
-
- case WM_LBUTTONUP:
- case WM_LBUTTONDOWN:
- case WM_RBUTTONUP:
- case WM_RBUTTONDOWN:
- case WM_LBUTTONDBLCLK:
- case WM_RBUTTONDBLCLK:
- if (msg == WM_LBUTTONDOWN)
- {
- HWND hWndParent;
- hWndParent = GetParent(hWnd);
- SendMessage(hWndParent, WM_UNHIGHLIGHT, 0, 0); // Send click message to page to unhighlight callout
- }
- GetClientRect(&wrect);
- point.x = int(LOWORD(lParam));
- point.y = int(HIWORD(lParam));
- bWithin = PtInRect(&wrect, point);
- break;
- case WM_TIMER:
- case WM_CAPTURECHANGED:
- break;
- default:
- return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
- }
-
- switch (msg)
- {
- case WM_LBUTTONDOWN:
- if (!GetReadOnly())
- StateEvent(bWithin ? FCBSE_DOWN : FCBSE_DOWNOFF);
- break;
-
- case WM_LBUTTONUP:
- if (!GetReadOnly())
- StateEvent(bWithin ? FCBSE_UPBOX : FCBSE_UPOFF);
- break;
- }
-
- return 0;
- }
-
- RECT CFlexComboBox::GetListBoxRect()
- {
- HWND hParent = GetParent(m_hWnd);
- RECT rect;
- GetClientRect(&rect);
- BOOL bRet = ClientToScreen(m_hWnd, &rect);
- BOOL bRet2 = ScreenToClient(hParent, &rect);
-
- RECT lrect = m_rect;
- lrect.top = rect.bottom;
- lrect.right -= 12; // UNDONE: remove this line when the clipping is working properly (scroll bars don't appear above other windows)
-
- return lrect;
- }
-
- void CFlexComboBox::DoSel()
- {
- if (m_bInSelMode)
- return;
-
- if (m_hWnd == NULL)
- return;
-
- FLEXLISTBOXCREATESTRUCT cs;
- cs.dwSize = sizeof(FLEXLISTBOXCREATESTRUCT);
- cs.dwFlags = m_dwListBoxFlags;
- cs.hWndParent = GetParent(m_hWnd);
- cs.hWndNotify = m_hWnd;
- cs.bVisible = FALSE;
- cs.rect = GetListBoxRect();
- cs.hFont = m_hFont;
- cs.rgbText = m_rgbText;
- cs.rgbBk = m_rgbBk;
- cs.rgbSelText = m_rgbSelText;
- cs.rgbSelBk = m_rgbSelBk;
- cs.rgbFill = m_rgbFill;
- cs.rgbLine = m_rgbLine;
- cs.nSBWidth = m_nSBWidth;
-
- m_OldSel = m_ListBox.GetSel();
-
- m_bInSelMode = m_ListBox.Create(&cs);
- if (m_bInSelMode)
- SetWindowPos(m_ListBox.m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
- }
-
- void CFlexComboBox::Notify(int code)
- {
- if (!m_hWndNotify)
- return;
-
- SendMessage(m_hWndNotify, WM_FLEXCOMBOBOX,
- (WPARAM)code, (LPARAM)(LPVOID)this);
- }
-
- RECT CFlexComboBox::GetRect(const RECT &rect)
- {
- int h = GetTextHeight(m_hFont);
- RECT ret = {rect.left, rect.top, rect.right, rect.top + h + 2};
- return ret;
- }
-
- RECT CFlexComboBox::GetRect()
- {
- RECT rect;
- GetClientRect(&rect);
- return GetRect(rect);
- }
-
- void CFlexComboBox::SetFont(HFONT hFont)
- {
- m_hFont = hFont;
-
- if (m_hWnd == NULL)
- return;
-
- Invalidate();
- SetRect();
- }
-
- void CFlexComboBox::SetRect()
- {
- if (m_hWnd == NULL)
- return;
-
- RECT rect = GetRect();
- SetWindowPos(m_hWnd, NULL, rect.left, rect.top, rect.right, rect.bottom, SWP_NOZORDER | SWP_NOMOVE);
- }
-
- void CFlexComboBox::SetColors(COLORREF text, COLORREF bk, COLORREF seltext, COLORREF selbk, COLORREF fill, COLORREF line)
- {
- m_rgbText = text;
- m_rgbBk = bk;
- m_rgbSelText = seltext;
- m_rgbSelBk = selbk;
- m_rgbFill = fill;
- m_rgbLine = line;
- Invalidate();
- }
-
- void CFlexComboBox::StateEvent(FCBSTATEEVENT e)
- {
- if (e == FCBSE_DOWNOFF)
- {
- SetState(FCBS_CANCEL);
- return;
- }
-
- switch (m_eCurState)
- {
- case FCBS_CLOSED:
- if (e == FCBSE_DOWN)
- SetState(FCBS_OPENDOWN);
- break;
-
- case FCBS_OPENDOWN:
- switch (e)
- {
- case FCBSE_UPLIST:
- SetState(FCBS_SELECT);
- break;
- case FCBSE_UPBOX:
- SetState(FCBS_OPENUP);
- break;
- case FCBSE_UPOFF:
- SetState(FCBS_CANCEL);
- break;
- }
-
- case FCBS_OPENUP:
- if (e == FCBSE_DOWN)
- SetState(FCBS_OPENDOWN);
- break;
-
- default:
- assert(0);
- return;
- }
- }
-
- void CFlexComboBox::SetState(FCBSTATE s)
- {
- FCBSTATE eOldState = m_eCurState;
- m_eCurState = s;
-
- switch (s)
- {
- case FCBS_OPENUP:
- if (eOldState == FCBS_CLOSED)
- DoSel();
- return;
-
- case FCBS_OPENDOWN:
- if (eOldState == FCBS_CLOSED)
- DoSel();
- m_ListBox.StartSel();
- return;
-
- case FCBS_CANCEL:
- m_ListBox.SetSel(m_OldSel);
- CFlexWnd::s_ToolTip.SetEnable(FALSE);
- SetState(FCBS_CLOSED);
- return;
-
- case FCBS_SELECT:
- CFlexWnd::s_ToolTip.SetEnable(FALSE);
- Invalidate();
- Notify(FCBN_SELCHANGE);
- SetState(FCBS_CLOSED);
- return;
-
- case FCBS_CLOSED:
- if (eOldState != FCBS_CLOSED)
- m_ListBox.Destroy();
- m_bInSelMode = FALSE;
- Invalidate();
- return;
- }
- }
-